package com.gun3y.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.htmlparser.Node;
import org.htmlparser.Tag;
import org.springframework.web.util.HtmlUtils;

import com.gun3y.entity.pattern.ExpressionType;
import com.gun3y.entity.pattern.FieldPatternExpression;

public class HtmlUtil {

    private HtmlUtil() {
	super();
    }

    public static final String LINKATTR = "href";

    public static final String SOURCEATTR = "src";

    public static String extractFrom(Node node, String attName, String defAttName, String baseUrl) {
	String retVal = "";
	if (node instanceof Tag) {
	    Tag tag = (Tag) node;
	    String tempAttName = "";

	    if (StringUtils.isNotBlank(attName)) {
		tempAttName = attName;
	    }
	    else {
		tempAttName = defAttName;
	    }
	    retVal = tag.getAttribute(tempAttName);

	    if (UrlUtil.needURLOperation(tempAttName, retVal)) {
		retVal = UrlUtil.createFullPath(baseUrl, retVal);
	    }

	    retVal = HtmlUtils.htmlUnescape(retVal);
	}

	return retVal;
    }

    public static String extractDate(Node node, String tagAttribute, List<FieldPatternExpression> expressions) {
	if (expressions == null || expressions.isEmpty() || expressions.get(0) == null
		|| StringUtils.isBlank(expressions.get(0).getPattern())) {
	    return StringUtils.EMPTY;
	}
	else {
	    String datePattern = expressions.get(0).getPattern();
	    String dateVal = HtmlUtil.extractText(node, tagAttribute);
	    return Commons.extractDate(dateVal, datePattern);
	}
    }

    public static String extractText(Node node, String attrName) {
	String val = StringUtils.EMPTY;

	if (node instanceof Tag && StringUtils.isNotBlank(attrName)) {
	    val = ((Tag) node).getAttribute(attrName);
	}
	else {
	    val = node.toPlainTextString().trim();
	}
	return HtmlUtils.htmlUnescape(val);

    }

    private static String extractRegex(String data, String regex, String group) {
	String retVal = "";
	if (StringUtils.isNotBlank(regex)) {
	    Pattern pattern = Pattern.compile(regex);
	    Matcher matcher = pattern.matcher(data);
	    if (matcher.find()) {
		if (StringUtils.isBlank(group)) {
		    retVal = matcher.group(0);
		}
		else if (StringUtils.isNumeric(group)) {
		    retVal = matcher.group(Integer.parseInt(group));
		}
		else {
		    Pattern groupPattern = Pattern.compile("\\{([0-9]+)\\}");
		    Matcher groupMatcher = groupPattern.matcher(group);

		    List<Integer> groupIndexes = new ArrayList<Integer>();
		    while (groupMatcher.find()) {
			groupIndexes.add(Integer.parseInt(groupMatcher.group(1)));
		    }

		    retVal = group;
		    for (Integer idx : groupIndexes) {
			retVal = retVal.replace("{" + idx + "}", matcher.group(idx));
		    }
		}
	    }
	}

	return retVal;
    }

    public static String extractStartEnd(String data, FieldPatternExpression exp1, FieldPatternExpression exp2) {
	String startPattern = "";
	String endPattern = "";
	String retVal = "";
	boolean startInc = false;
	boolean endInc = false;

	if (exp1.getExpressionType() == ExpressionType.StartWith) {
	    startPattern = exp1.getPattern();
	    startInc = exp1.isInclusive();

	    if (exp2 != null && exp2.getExpressionType() == ExpressionType.EndWith) {
		endPattern = exp2.getPattern();
		endInc = exp2.isInclusive();
	    }

	}
	else if (exp1.getExpressionType() == ExpressionType.EndWith) {

	    endPattern = exp1.getPattern();
	    endInc = exp1.isInclusive();

	    if (exp2 != null && exp2.getExpressionType() == ExpressionType.StartWith) {
		startPattern = exp2.getPattern();
		startInc = exp2.isInclusive();
	    }
	}
	if (startPattern != null) {
	    startPattern = startPattern.replaceAll("\\W", "\\\\$0");
	}
	if (endPattern != null) {
	    endPattern = endPattern.replaceAll("\\W", "\\\\$0");
	}
	if (StringUtils.isNotBlank(startPattern) && StringUtils.isNotBlank(endPattern)) {
	    Pattern pattern = Pattern.compile("(" + startPattern + ")((\\W|\\w)+)(" + endPattern + ")");
	    Matcher matcher = pattern.matcher(data);
	    if (matcher.find()) {

		if (startInc) {
		    retVal = retVal + matcher.group(1);
		}
		retVal = retVal + matcher.group(2);

		if (endInc) {
		    retVal = retVal + matcher.group(4);
		}
	    }
	}
	else if (StringUtils.isNotBlank(startPattern)) {
	    Pattern pattern = Pattern.compile("(" + startPattern + ")((\\W|\\w)+)");
	    Matcher matcher = pattern.matcher(data);
	    if (matcher.find()) {

		if (startInc) {
		    retVal = retVal + matcher.group(1);
		}
		retVal = retVal + matcher.group(2);
	    }
	}
	else if (StringUtils.isNotBlank(endPattern)) {
	    Pattern pattern = Pattern.compile("((\\W|\\w)+)(" + endPattern + ")");
	    Matcher matcher = pattern.matcher(data);
	    if (matcher.find()) {

		retVal = retVal + matcher.group(1);

		if (endInc) {
		    retVal = retVal + matcher.group(3);
		}
	    }
	}
	else {
	    retVal = data;
	}

	return retVal;
    }

    private static List<String> extractSplit(String data, String pattern) {
	List<String> retList = new ArrayList<String>();
	if (StringUtils.isNotBlank(pattern) && StringUtils.isNotBlank(data)) {
	    String[] splittedData = data.split(pattern);
	    if (splittedData != null && splittedData.length > 0) {
		for (String si : splittedData) {
		    if (StringUtils.isNotBlank(si)) {
			retList.add(si.trim());
		    }
		}
	    }
	}

	return retList;
    }

    public static List<String> extractCustom(String data, FieldPatternExpression exp1, FieldPatternExpression exp2) {
	List<String> items = new ArrayList<String>();

	if (exp1 != null) {
	    switch (exp1.getExpressionType()) {
	    case Split:
		items.addAll(extractSplit(data, exp1.getPattern()));
		break;
	    case StartWith:
	    case EndWith:
		String starEnd = extractStartEnd(data, exp1, exp2);
		items.add(starEnd);
		break;
	    case RegEx:
		String accVal = extractRegex(data, exp1.getPattern(), exp1.getGroup());
		items.add(accVal);
		break;
	    default:
		break;
	    }
	}

	return items;
    }

    public static List<String> extractCustom(Node node, String attrName, List<FieldPatternExpression> expressions) {
	if (node == null || expressions == null || expressions.isEmpty()) {
	    return new ArrayList<String>();
	}

	FieldPatternExpression exp1 = expressions.get(0);
	FieldPatternExpression exp2 = null;

	if (expressions.size() > 1) {
	    exp2 = expressions.get(1);
	}

	String data = extractText(node, attrName);
	return extractCustom(data, exp1, exp2);
    }

}
